﻿using System;
using System.Collections.Generic;
using System.Drawing;

namespace PlusPlusPaint.Layers
{
    /* Guidelines for variable naming:
     * 
     * - c for values relative to canvas
     * - l for values relative to layer
     * - s for values relative to anything sub-layer (s1, s2, s3... if you use multilple)
     * - x for horizontal
     * - y for vertical
     * - i for index
     * - U for anything that is not relative to the top-left corner
     * 
     * All positions not specified with U are relative to the top-left corner
     * of whatever they are relative to.  Notice that a size is just the
     * UlDistance to the bottom-right corner relative to oneself.
     * 
     * Prefer raw ints over points and sizes where possible (easier to change),
     * but don't expose them to other classes, and provide both overloads where
     * possible.
     */
    interface ILayer
    {
        #region properties
        /// <summary>
        /// The position of the top-left corner of the layer relative to the
        /// canvas.
        /// </summary>
        Point Location
        {
            get;
        }

        /// <summary>
        /// The horizontal and vertical dimensions of the layer.
        /// </summary>
        Size Size
        {
            get;
        }

        /// <summary>
        /// The union of the location and the size.
        /// </summary>
        Rectangle ClientRectangle
        {
            get;
        }

        /// <summary>
        /// Indicates whether the layer can be freely drawn on;  in other
        /// words, whether any pixel of the layer may be set to any value at
        /// will.
        /// </summary>
        bool CanFreeDraw
        {
            get;
        }

        /// <summary>
        /// Indicates whether the visual representation given by the layer
        /// should be displayed to the user.
        /// </summary>
        bool Visible
        {
            get;
            set;
        }

        /// <summary>
        /// Indicates whether it makes any sense to call Explode() on the layer.
        /// The layer should still react to the Explode function in some
        /// documented way.
        /// </summary>
        bool Explodable
        {
            get;
        }

        string Name
        {
            get;
            set;
        }
        #endregion

        #region methods
        /// <summary>
        /// Return true if the specified point is within the hitbox of the
        /// layer.
        /// </summary>
        bool PositionIsInHitbox(Point p);

        /// <summary>
        /// Attempt to apply the given tool to the given point.  This should
        /// always succeed when using the LayerManager, as the LayerManager
        /// must ensure that it is applying the tool to a layer that can take
        /// it.
        /// </summary>
        void ApplyToolToPoint(Tools.ISketchTool t, Point p);

        /// <summary>
        /// Return true if the given tool is willing to operate on the layer.
        /// </summary>
        bool CanHaveToolApplied(Tools.ISketchTool t);

        /// <summary>
        /// Return a list of all layers contained.
        /// </summary>
        /// <remarks>
        /// If there are no layers contained, just return a list containing
        /// only the layer itself.
        /// </remarks>
        IList<ILayer> ExplodeLayer();

        /// <summary>
        /// Draw the visual representation of the layer on the given image.
        /// This function should not respect visibility.
        /// </summary>
        void BurnOn(Image i);

        /// <summary>
        /// Return a copy of the instance.
        /// </summary>
        ILayer Clone();

        /// <summary>
        /// Remove the layer from existence.
        /// </summary>
        void Delete();

        /// <summary>
        /// Add a method to call when the layer is deleted.
        /// </summary>
        void CallOnDeletion(Action f);

        /// <summary>
        /// Force the layer to be redrawn.
        /// </summary>
        void Invalidate();

        /// <summary>
        /// Register a method to be called when the layer must be redrawn.
        /// </summary>
        void CallOnInvalidate(EventHandler eh);

        /// <summary>
        /// Return a serialized version of this instance, ready to be written
        /// to disk.
        /// </summary>
        SerializedObject Serialize();

        /// <summary>
        /// Initialise this instance from serialized data.
        /// </summary>
        void Deserialize(SerializedObject s);
        #endregion
    }
}
